#ifdef C_CORE
#define NEG(i) ((i) >> 31)
#define POS(i) ((~(i)) >> 31)
#define ADDCARRY(a, b, c) \
    C_FLAG = ((NEG(a) & NEG(b)) | \
              (NEG(a) & POS(c)) | \
              (NEG(b) & POS(c))) ? true : false;
#define ADDOVERFLOW(a, b, c) \
    V_FLAG = ((NEG(a) & NEG(b) & POS(c)) | \
              (POS(a) & POS(b) & NEG(c))) ? true : false;
#define SUBCARRY(a, b, c) \
    C_FLAG = ((NEG(a) & POS(b)) | \
              (NEG(a) & POS(c)) | \
              (POS(b) & POS(c))) ? true : false;
#define SUBOVERFLOW(a, b, c) \
    V_FLAG = ((NEG(a) & POS(b) & POS(c)) | \
              (POS(a) & NEG(b) & NEG(c))) ? true : false;
#define ADD_RD_RS_RN \
	{ \
		u32 lhs = reg[source].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define ADD_RD_RS_O3 \
	{ \
		u32 lhs = reg[source].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define ADD_RN_O8(d) \
	{ \
		u32 lhs = reg[(d)].I; \
		u32 rhs = (opcode & 255); \
		u32 res = lhs + rhs; \
		reg[(d)].I = res; \
		Z_FLAG	   = (res == 0) ? true : false; \
		N_FLAG	   = NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define CMN_RD_RS \
	{ \
		u32 lhs = reg[dest].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs; \
		Z_FLAG = (res == 0) ? true : false; \
		N_FLAG = NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define ADC_RD_RS \
	{ \
		u32 lhs = reg[dest].I; \
		u32 rhs = value; \
		u32 res = lhs + rhs + (u32)C_FLAG; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		ADDCARRY(lhs, rhs, res); \
		ADDOVERFLOW(lhs, rhs, res); \
	}
#define SUB_RD_RS_RN \
	{ \
		u32 lhs = reg[source].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define SUB_RD_RS_O3 \
	{ \
		u32 lhs = reg[source].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define SUB_RN_O8(d) \
	{ \
		u32 lhs = reg[(d)].I; \
		u32 rhs = (opcode & 255); \
		u32 res = lhs - rhs; \
		reg[(d)].I = res; \
		Z_FLAG	   = (res == 0) ? true : false; \
		N_FLAG	   = NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define CMP_RN_O8(d) \
	{ \
		u32 lhs = reg[(d)].I; \
		u32 rhs = (opcode & 255); \
		u32 res = lhs - rhs; \
		Z_FLAG = (res == 0) ? true : false; \
		N_FLAG = NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define SBC_RD_RS \
	{ \
		u32 lhs = reg[dest].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs - !((u32)C_FLAG); \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#define LSL_RD_RM_I5 \
	{ \
		C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \
		value  = reg[source].I << shift; \
	}
#define LSL_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \
		value  = reg[dest].I << value; \
	}
#define LSR_RD_RM_I5 \
	{ \
		C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \
		value  = reg[source].I >> shift; \
	}
#define LSR_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
		value  = reg[dest].I >> value; \
	}
#define ASR_RD_RM_I5 \
	{ \
		C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \
		value  = (s32)reg[source].I >> (int)shift; \
	}
#define ASR_RD_RS \
	{ \
		C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \
		value  = (s32)reg[dest].I >> (int)value; \
	}
#define ROR_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
		value  = ((reg[dest].I << (32 - value)) | \
		          (reg[dest].I >> value)); \
	}
#define NEG_RD_RS \
	{ \
		u32 lhs = reg[source].I; \
		u32 rhs = 0; \
		u32 res = rhs - lhs; \
		reg[dest].I = res; \
		Z_FLAG		= (res == 0) ? true : false; \
		N_FLAG		= NEG(res) ? true : false; \
		SUBCARRY(rhs, lhs, res); \
		SUBOVERFLOW(rhs, lhs, res); \
	}
#define CMP_RD_RS \
	{ \
		u32 lhs = reg[dest].I; \
		u32 rhs = value; \
		u32 res = lhs - rhs; \
		Z_FLAG = (res == 0) ? true : false; \
		N_FLAG = NEG(res) ? true : false; \
		SUBCARRY(lhs, rhs, res); \
		SUBOVERFLOW(lhs, rhs, res); \
	}
#else
#ifdef __GNUC__
#ifdef __POWERPC__
			#define ADD_RD_RS_RN \
	{                                       \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("addco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[source].I),  \
		              "r" (value)           \
		              );                      \
		reg[dest].I = Result;               \
		Z_FLAG		= (Flags >> 29) & 1;         \
		N_FLAG		= (Flags >> 31) & 1;         \
		C_FLAG		= (Flags >> 25) & 1;         \
		V_FLAG		= (Flags >> 26) & 1;         \
	}
			#define ADD_RD_RS_O3 ADD_RD_RS_RN
			#define ADD_RN_O8(d) \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("addco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[(d)].I),     \
		              "r" (opcode & 255)    \
		              );                      \
		reg[(d)].I = Result;                \
		Z_FLAG	   = (Flags >> 29) & 1;         \
		N_FLAG	   = (Flags >> 31) & 1;         \
		C_FLAG	   = (Flags >> 25) & 1;         \
		V_FLAG	   = (Flags >> 26) & 1;         \
	}
			#define CMN_RD_RS \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("addco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[dest].I),    \
		              "r" (value)           \
		              );                      \
		Z_FLAG = (Flags >> 29) & 1;         \
		N_FLAG = (Flags >> 31) & 1;         \
		C_FLAG = (Flags >> 25) & 1;         \
		V_FLAG = (Flags >> 26) & 1;         \
	}
			#define ADC_RD_RS \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("mtspr xer, %4\n"      \
		              "addeo. %0, %2, %3\n"  \
		              "mcrxr cr1\n"          \
		              "mfcr	%1\n"            \
					  : "=r" (Result),       \
		              "=r" (Flags)         \
					  : "r" (reg[dest].I),   \
		              "r" (value),         \
		              "r" (C_FLAG << 29)   \
		              );                     \
		reg[dest].I = Result;               \
		Z_FLAG		= (Flags >> 29) & 1;         \
		N_FLAG		= (Flags >> 31) & 1;         \
		C_FLAG		= (Flags >> 25) & 1;         \
		V_FLAG		= (Flags >> 26) & 1;         \
	}
			#define SUB_RD_RS_RN \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("subco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[source].I),  \
		              "r" (value)           \
		              );                      \
		reg[dest].I = Result;               \
		Z_FLAG		= (Flags >> 29) & 1;         \
		N_FLAG		= (Flags >> 31) & 1;         \
		C_FLAG		= (Flags >> 25) & 1;         \
		V_FLAG		= (Flags >> 26) & 1;         \
	}
			#define SUB_RD_RS_O3 SUB_RD_RS_RN
			#define SUB_RN_O8(d) \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("subco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[(d)].I),     \
		              "r" (opcode & 255)    \
		              );                      \
		reg[(d)].I = Result;                \
		Z_FLAG	   = (Flags >> 29) & 1;         \
		N_FLAG	   = (Flags >> 31) & 1;         \
		C_FLAG	   = (Flags >> 25) & 1;         \
		V_FLAG	   = (Flags >> 26) & 1;         \
	}
			#define CMP_RN_O8(d) \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("subco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[(d)].I),     \
		              "r" (opcode & 255)    \
		              );                      \
		Z_FLAG = (Flags >> 29) & 1;         \
		N_FLAG = (Flags >> 31) & 1;         \
		C_FLAG = (Flags >> 25) & 1;         \
		V_FLAG = (Flags >> 26) & 1;         \
	}
			#define SBC_RD_RS \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("mtspr xer, %4\n"      \
		              "subfeo. %0, %3, %2\n" \
		              "mcrxr cr1\n"          \
		              "mfcr	%1\n"            \
					  : "=r" (Result),       \
		              "=r" (Flags)         \
					  : "r" (reg[dest].I),   \
		              "r" (value),         \
		              "r" (C_FLAG << 29)   \
		              );                     \
		reg[dest].I = Result;               \
		Z_FLAG		= (Flags >> 29) & 1;         \
		N_FLAG		= (Flags >> 31) & 1;         \
		C_FLAG		= (Flags >> 25) & 1;         \
		V_FLAG		= (Flags >> 26) & 1;         \
	}
			#define LSL_RD_RM_I5 \
	{ \
		C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \
		value  = reg[source].I << shift; \
	}
			#define LSL_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \
		value  = reg[dest].I << value; \
	}
			#define LSR_RD_RM_I5 \
	{ \
		C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \
		value  = reg[source].I >> shift; \
	}
			#define LSR_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
		value  = reg[dest].I >> value; \
	}
			#define ASR_RD_RM_I5 \
	{ \
		C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \
		value  = (s32)reg[source].I >> (int)shift; \
	}
			#define ASR_RD_RS \
	{ \
		C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \
		value  = (s32)reg[dest].I >> (int)value; \
	}
			#define ROR_RD_RS \
	{ \
		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
		value  = ((reg[dest].I << (32 - value)) | \
		          (reg[dest].I >> value)); \
	}
			#define NEG_RD_RS \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("subfco. %0, %2, %3\n" \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[source].I),  \
		              "r" (0)               \
		              );                      \
		reg[dest].I = Result;               \
		Z_FLAG		= (Flags >> 29) & 1;         \
		N_FLAG		= (Flags >> 31) & 1;         \
		C_FLAG		= (Flags >> 25) & 1;         \
		V_FLAG		= (Flags >> 26) & 1;         \
	}
			#define CMP_RD_RS \
	{ \
		register int Flags;                 \
		register int Result;                \
		asm volatile ("subco. %0, %2, %3\n"  \
		              "mcrxr cr1\n"           \
		              "mfcr %1\n"             \
					  : "=r" (Result),        \
		              "=r" (Flags)          \
					  : "r" (reg[dest].I),    \
		              "r" (value)           \
		              );                      \
		Z_FLAG = (Flags >> 29) & 1;         \
		N_FLAG = (Flags >> 31) & 1;         \
		C_FLAG = (Flags >> 25) & 1;         \
		V_FLAG = (Flags >> 26) & 1;         \
	}
#else
#define ADD_RD_RS_RN \
    asm ("add %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setcb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[source].I));
#define ADD_RD_RS_O3 \
    asm ("add %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setcb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[source].I));
#define ADD_RN_O8(d) \
    asm ("add %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setcb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[(d)].I) \
		 : "r" (opcode & 255), "b" (reg[(d)].I));
#define CMN_RD_RS \
    asm ("add %0, %1;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setcb C_FLAG;" \
         "setob V_FLAG;" \
		 : \
		 : "r" (value), "r" (reg[dest].I) : "1");
#define ADC_RD_RS \
    asm ("bt $0, C_FLAG;" \
         "adc %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setcb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[dest].I));
#define SUB_RD_RS_RN \
    asm ("sub %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[source].I));
#define SUB_RD_RS_O3 \
    asm ("sub %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "r" (value), "b" (reg[source].I));
#define SUB_RN_O8(d) \
    asm ("sub %1, %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[(d)].I) \
		 : "r" (opcode & 255), "b" (reg[(d)].I));
#define CMP_RN_O8(d) \
    asm ("sub %0, %1;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : \
		 : "r" (opcode & 255), "r" (reg[(d)].I) : "1");
#define SBC_RD_RS \
    asm volatile ("bt $0, C_FLAG;" \
                  "cmc;" \
                  "sbb %1, %%ebx;" \
                  "setsb N_FLAG;" \
                  "setzb Z_FLAG;" \
                  "setncb C_FLAG;" \
                  "setob V_FLAG;" \
				  : "=b" (reg[dest].I) \
				  : "r" (value), "b" (reg[dest].I) : "cc", "memory");
#define LSL_RD_RM_I5 \
    asm ("shl %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[source].I), "c" (shift));
#define LSL_RD_RS \
    asm ("shl %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[dest].I), "c" (value));
#define LSR_RD_RM_I5 \
    asm ("shr %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[source].I), "c" (shift));
#define LSR_RD_RS \
    asm ("shr %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[dest].I), "c" (value));
#define ASR_RD_RM_I5 \
    asm ("sar %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[source].I), "c" (shift));
#define ASR_RD_RS \
    asm ("sar %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[dest].I), "c" (value));
#define ROR_RD_RS \
    asm ("ror %%cl, %%eax;" \
         "setcb C_FLAG;" \
		 : "=a" (value) \
		 : "a" (reg[dest].I), "c" (value));
#define NEG_RD_RS \
    asm ("neg %%ebx;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : "=b" (reg[dest].I) \
		 : "b" (reg[source].I));
#define CMP_RD_RS \
    asm ("sub %0, %1;" \
         "setsb N_FLAG;" \
         "setzb Z_FLAG;" \
         "setncb C_FLAG;" \
         "setob V_FLAG;" \
		 : \
		 : "r" (value), "r" (reg[dest].I) : "1");
#endif
#else
#define ADD_RD_RS_RN \
	{ \
		__asm mov eax, source \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm add ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define ADD_RD_RS_O3 \
	{ \
		__asm mov eax, source \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm add ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define ADD_RN_O8(d) \
	{ \
		__asm mov ebx, opcode \
		          __asm and ebx, 255 \
		__asm add dword ptr [OFFSET reg + 4 * (d)], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define CMN_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm add ebx, value \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define ADC_RD_RS \
	{ \
		__asm mov ebx, dest \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm bt word ptr C_FLAG, 0 \
		__asm adc ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define SUB_RD_RS_RN \
	{ \
		__asm mov eax, source \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm sub ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define SUB_RD_RS_O3 \
	{ \
		__asm mov eax, source \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm sub ebx, value \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define SUB_RN_O8(d) \
	{ \
		__asm mov ebx, opcode \
		          __asm and ebx, 255 \
		__asm sub dword ptr [OFFSET reg + 4 * (d)], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define CMP_RN_O8(d) \
	{ \
		__asm mov eax, dword ptr [OFFSET reg + 4 * (d)] \
		__asm mov ebx, opcode \
		          __asm and ebx, 255 \
		__asm sub eax, ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define SBC_RD_RS \
	{ \
		__asm mov ebx, dest \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm mov eax, value \
		__asm bt word ptr C_FLAG, 0 \
		__asm cmc \
		__asm sbb ebx, eax \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define LSL_RD_RM_I5 \
	{ \
		__asm mov eax, source \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr shift \
		__asm shl eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define LSL_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr value \
		__asm shl eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define LSR_RD_RM_I5 \
	{ \
		__asm mov eax, source \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr shift \
		__asm shr eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define LSR_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr value \
		__asm shr eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define ASR_RD_RM_I5 \
	{ \
		__asm mov eax, source \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr shift \
		__asm sar eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define ASR_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr value \
		__asm sar eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define ROR_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
		__asm mov cl, byte ptr value \
		__asm ror eax, cl \
		__asm mov value, eax \
		__asm setc byte ptr C_FLAG \
	}
#define NEG_RD_RS \
	{ \
		__asm mov ebx, source \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
		__asm neg ebx \
		__asm mov eax, dest \
		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#define CMP_RD_RS \
	{ \
		__asm mov eax, dest \
		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
		__asm sub ebx, value \
		__asm sets byte ptr N_FLAG \
		__asm setz byte ptr Z_FLAG \
		__asm setnc byte ptr C_FLAG \
		__asm seto byte ptr V_FLAG \
	}
#endif
#endif

u32 opcode = CPUReadHalfWordQuick(armNextPC);
clockTicks = thumbCycles[opcode >> 8] + memoryWaitFetch[(armNextPC >> 24) & 15];
#ifndef FINAL_VERSION
if (armNextPC == armStopAddr)
{
	armNextPC = armNextPC++;
}
#endif

armNextPC  = reg[15].I;
reg[15].I += 2;

switch (opcode >> 8)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
{
	// LSL Rd, Rm, #Imm 5
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	int shift  = (opcode >> 6) & 0x1f;
	u32 value;

	if (shift)
	{
		LSL_RD_RM_I5;
	}
	else
	{
		value = reg[source].I;
	}
	reg[dest].I = value;
	// C_FLAG set above
	N_FLAG = (value & 0x80000000 ? true : false);
	Z_FLAG = (value ? false : true);
}
break;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
{
	// LSR Rd, Rm, #Imm 5
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	int shift  = (opcode >> 6) & 0x1f;
	u32 value;

	if (shift)
	{
		LSR_RD_RM_I5;
	}
	else
	{
		C_FLAG = reg[source].I & 0x80000000 ? true : false;
		value  = 0;
	}
	reg[dest].I = value;
	// C_FLAG set above
	N_FLAG = (value & 0x80000000 ? true : false);
	Z_FLAG = (value ? false : true);
}
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
{
	// ASR Rd, Rm, #Imm 5
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	int shift  = (opcode >> 6) & 0x1f;
	u32 value;

	if (shift)
	{
		ASR_RD_RM_I5;
	}
	else
	{
		if (reg[source].I & 0x80000000)
		{
			value  = 0xFFFFFFFF;
			C_FLAG = true;
		}
		else
		{
			value  = 0;
			C_FLAG = false;
		}
	}
	reg[dest].I = value;
	// C_FLAG set above
	N_FLAG = (value & 0x80000000 ? true : false);
	Z_FLAG = (value ? false : true);
}
break;
case 0x18:
case 0x19:
{
	// ADD Rd, Rs, Rn
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	u32 value  = reg[(opcode >> 6) & 0x07].I;
	ADD_RD_RS_RN;
}
break;
case 0x1a:
case 0x1b:
{
	// SUB Rd, Rs, Rn
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	u32 value  = reg[(opcode >> 6) & 0x07].I;
	SUB_RD_RS_RN;
}
break;
case 0x1c:
case 0x1d:
{
	// ADD Rd, Rs, #Offset3
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	u32 value  = (opcode >> 6) & 7;
	ADD_RD_RS_O3;
}
break;
case 0x1e:
case 0x1f:
{
	// SUB Rd, Rs, #Offset3
	int dest   = opcode & 0x07;
	int source = (opcode >> 3) & 0x07;
	u32 value  = (opcode >> 6) & 7;
	SUB_RD_RS_O3;
}
break;
case 0x20:
	// MOV R0, #Offset8
	reg[0].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[0].I ? false : true);
	break;
case 0x21:
	// MOV R1, #Offset8
	reg[1].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[1].I ? false : true);
	break;
case 0x22:
	// MOV R2, #Offset8
	reg[2].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[2].I ? false : true);
	break;
case 0x23:
	// MOV R3, #Offset8
	reg[3].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[3].I ? false : true);
	break;
case 0x24:
	// MOV R4, #Offset8
	reg[4].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[4].I ? false : true);
	break;
case 0x25:
	// MOV R5, #Offset8
	reg[5].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[5].I ? false : true);
	break;
case 0x26:
	// MOV R6, #Offset8
	reg[6].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[6].I ? false : true);
	break;
case 0x27:
	// MOV R7, #Offset8
	reg[7].I = opcode & 255;
	N_FLAG	 = false;
	Z_FLAG	 = (reg[7].I ? false : true);
	break;
case 0x28:
	// CMP R0, #Offset8
	CMP_RN_O8(0);
	break;
case 0x29:
	// CMP R1, #Offset8
	CMP_RN_O8(1);
	break;
case 0x2a:
	// CMP R2, #Offset8
	CMP_RN_O8(2);
	break;
case 0x2b:
	// CMP R3, #Offset8
	CMP_RN_O8(3);
	break;
case 0x2c:
	// CMP R4, #Offset8
	CMP_RN_O8(4);
	break;
case 0x2d:
	// CMP R5, #Offset8
	CMP_RN_O8(5);
	break;
case 0x2e:
	// CMP R6, #Offset8
	CMP_RN_O8(6);
	break;
case 0x2f:
	// CMP R7, #Offset8
	CMP_RN_O8(7);
	break;
case 0x30:
	// ADD R0,#Offset8
	ADD_RN_O8(0);
	break;
case 0x31:
	// ADD R1,#Offset8
	ADD_RN_O8(1);
	break;
case 0x32:
	// ADD R2,#Offset8
	ADD_RN_O8(2);
	break;
case 0x33:
	// ADD R3,#Offset8
	ADD_RN_O8(3);
	break;
case 0x34:
	// ADD R4,#Offset8
	ADD_RN_O8(4);
	break;
case 0x35:
	// ADD R5,#Offset8
	ADD_RN_O8(5);
	break;
case 0x36:
	// ADD R6,#Offset8
	ADD_RN_O8(6);
	break;
case 0x37:
	// ADD R7,#Offset8
	ADD_RN_O8(7);
	break;
case 0x38:
	// SUB R0,#Offset8
	SUB_RN_O8(0);
	break;
case 0x39:
	// SUB R1,#Offset8
	SUB_RN_O8(1);
	break;
case 0x3a:
	// SUB R2,#Offset8
	SUB_RN_O8(2);
	break;
case 0x3b:
	// SUB R3,#Offset8
	SUB_RN_O8(3);
	break;
case 0x3c:
	// SUB R4,#Offset8
	SUB_RN_O8(4);
	break;
case 0x3d:
	// SUB R5,#Offset8
	SUB_RN_O8(5);
	break;
case 0x3e:
	// SUB R6,#Offset8
	SUB_RN_O8(6);
	break;
case 0x3f:
	// SUB R7,#Offset8
	SUB_RN_O8(7);
	break;
case 0x40:
	switch ((opcode >> 6) & 3)
	{
	case 0x00:
	{
		// AND Rd, Rs
		int dest = opcode & 7;
		reg[dest].I &= reg[(opcode >> 3) & 7].I;
		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG		 = reg[dest].I ? false : true;
#ifdef BKPT_SUPPORT
#define THUMB_CONSOLE_OUTPUT(a, b) \
	if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \
		extern void (*dbgOutput)(const char *, u32); \
		dbgOutput((a), (b)); \
	}
#else
#define THUMB_CONSOLE_OUTPUT(a, b)
#endif
		THUMB_CONSOLE_OUTPUT(NULL, reg[2].I);
	}
	break;
	case 0x01:
		// EOR Rd, Rs
	{
		int dest = opcode & 7;
		reg[dest].I ^= reg[(opcode >> 3) & 7].I;
		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG		 = reg[dest].I ? false : true;
	}
	break;
	case 0x02:
		// LSL Rd, Rs
	{
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].B.B0;
		if (value)
		{
			if (value == 32)
			{
				value  = 0;
				C_FLAG = (reg[dest].I & 1 ? true : false);
			}
			else if (value < 32)
			{
				LSL_RD_RS;
			}
			else
			{
				value  = 0;
				C_FLAG = false;
			}
			reg[dest].I = value;
		}
		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG = reg[dest].I ? false : true;
		clockTicks++;
	}
	break;
	case 0x03:
	{
		// LSR Rd, Rs
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].B.B0;
		if (value)
		{
			if (value == 32)
			{
				value  = 0;
				C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
			}
			else if (value < 32)
			{
				LSR_RD_RS;
			}
			else
			{
				value  = 0;
				C_FLAG = false;
			}
			reg[dest].I = value;
		}
		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG = reg[dest].I ? false : true;
		clockTicks++;
	}
	break;
	}
	break;
case 0x41:
	switch ((opcode >> 6) & 3)
	{
	case 0x00:
	{
		// ASR Rd, Rs
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].B.B0;
		// ASR
		if (value)
		{
			if (value < 32)
			{
				ASR_RD_RS;
				reg[dest].I = value;
			}
			else
			{
				if (reg[dest].I & 0x80000000)
				{
					reg[dest].I = 0xFFFFFFFF;
					C_FLAG		= true;
				}
				else
				{
					reg[dest].I = 0x00000000;
					C_FLAG		= false;
				}
			}
		}
		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG = reg[dest].I ? false : true;
		clockTicks++;
	}
	break;
	case 0x01:
	{
		// ADC Rd, Rs
		int dest  = opcode & 0x07;
		u32 value = reg[(opcode >> 3) & 7].I;
		// ADC
		ADC_RD_RS;
	}
	break;
	case 0x02:
	{
		// SBC Rd, Rs
		int dest  = opcode & 0x07;
		u32 value = reg[(opcode >> 3) & 7].I;

		// SBC
		SBC_RD_RS;
	}
	break;
	case 0x03:
		// ROR Rd, Rs
	{
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].B.B0;

		if (value)
		{
			value = value & 0x1f;
			if (value == 0)
			{
				C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
			}
			else
			{
				ROR_RD_RS;
				reg[dest].I = value;
			}
		}
		clockTicks++;
		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
		Z_FLAG = reg[dest].I ? false : true;
	}
	break;
	}
	break;
case 0x42:
	switch ((opcode >> 6) & 3)
	{
	case 0x00:
	{
		// TST Rd, Rs
		u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I;
		N_FLAG = value & 0x80000000 ? true : false;
		Z_FLAG = value ? false : true;
	}
	break;
	case 0x01:
	{
		// NEG Rd, Rs
		int dest   = opcode & 7;
		int source = (opcode >> 3) & 7;
		NEG_RD_RS;
	}
	break;
	case 0x02:
	{
		// CMP Rd, Rs
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].I;
		CMP_RD_RS;
	}
	break;
	case 0x03:
	{
		// CMN Rd, Rs
		int dest  = opcode & 7;
		u32 value = reg[(opcode >> 3) & 7].I;
		// CMN
		CMN_RD_RS;
	}
	break;
	}
	break;
case 0x43:
	switch ((opcode >> 6) & 3)
	{
	case 0x00:
	{
		// ORR Rd, Rs
		int dest = opcode & 7;
		reg[dest].I |= reg[(opcode >> 3) & 7].I;
		Z_FLAG		 = reg[dest].I ? false : true;
		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
	}
	break;
	case 0x01:
	{
		// MUL Rd, Rs
		int dest = opcode & 7;
		u32 rm	 = reg[(opcode >> 3) & 7].I;
		reg[dest].I = reg[dest].I * rm;
		if (((s32)rm) < 0)
			rm = ~rm;
		if ((rm & 0xFFFFFF00) == 0)
			clockTicks += 1;
		else if ((rm & 0xFFFF0000) == 0)
			clockTicks += 2;
		else if ((rm & 0xFF000000) == 0)
			clockTicks += 3;
		else
			clockTicks += 4;
		Z_FLAG = reg[dest].I ? false : true;
		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
	}
	break;
	case 0x02:
	{
		// BIC Rd, Rs
		int dest = opcode & 7;
		reg[dest].I &= (~reg[(opcode >> 3) & 7].I);
		Z_FLAG		 = reg[dest].I ? false : true;
		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
	}
	break;
	case 0x03:
	{
		// MVN Rd, Rs
		int dest = opcode & 7;
		reg[dest].I = ~reg[(opcode >> 3) & 7].I;
		Z_FLAG		= reg[dest].I ? false : true;
		N_FLAG		= reg[dest].I & 0x80000000 ? true : false;
	}
	break;
	}
	break;
case 0x44:
{
	int dest = opcode & 7;
	int base = (opcode >> 3) & 7;
	switch ((opcode >> 6) & 3)
	{
	default:
		goto unknown_thumb;
	case 1:
		// ADD Rd, Hs
		reg[dest].I += reg[base + 8].I;
		break;
	case 2:
		// ADD Hd, Rs
		reg[dest + 8].I += reg[base].I;
		if (dest == 7)
		{
			reg[15].I &= 0xFFFFFFFE;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
			clockTicks++;
		}
		break;
	case 3:
		// ADD Hd, Hs
		reg[dest + 8].I += reg[base + 8].I;
		if (dest == 7)
		{
			reg[15].I &= 0xFFFFFFFE;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
			clockTicks++;
		}
		break;
	}
}
break;
case 0x45:
{
	int dest = opcode & 7;
	int base = (opcode >> 3) & 7;
	u32 value;
	switch ((opcode >> 6) & 3)
	{
	case 0:
		// CMP Rd, Hs
		value = reg[base].I;
		CMP_RD_RS;
		break;
	case 1:
		// CMP Rd, Hs
		value = reg[base + 8].I;
		CMP_RD_RS;
		break;
	case 2:
		// CMP Hd, Rs
		value = reg[base].I;
		dest += 8;
		CMP_RD_RS;
		break;
	case 3:
		// CMP Hd, Hs
		value = reg[base + 8].I;
		dest += 8;
		CMP_RD_RS;
		break;
	}
}
break;
case 0x46:
{
	int dest = opcode & 7;
	int base = (opcode >> 3) & 7;
	switch ((opcode >> 6) & 3)
	{
	case 0:
		// this form should not be used...
		// MOV Rd, Rs
		reg[dest].I = reg[base].I;
		break;
	case 1:
		// MOV Rd, Hs
		reg[dest].I = reg[base + 8].I;
		break;
	case 2:
		// MOV Hd, Rs
		reg[dest + 8].I = reg[base].I;
		if (dest == 7)
		{
			reg[15].I &= 0xFFFFFFFE;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
			clockTicks++;
		}
		break;
	case 3:
		// MOV Hd, Hs
		reg[dest + 8].I = reg[base + 8].I;
		if (dest == 7)
		{
			reg[15].I &= 0xFFFFFFFE;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
			clockTicks++;
		}
		break;
	}
}
break;
case 0x47:
{
	int base = (opcode >> 3) & 7;
	switch ((opcode >> 6) & 3)
	{
	case 0:
		// BX Rs
		reg[15].I = (reg[base].I) & 0xFFFFFFFE;
		if (reg[base].I & 1)
		{
			armState   = false;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
		}
		else
		{
			armState   = true;
			reg[15].I &= 0xFFFFFFFC;
			armNextPC  = reg[15].I;
			reg[15].I += 4;
		}
		break;
	case 1:
		// BX Hs
		reg[15].I = (reg[8 + base].I) & 0xFFFFFFFE;
		if (reg[8 + base].I & 1)
		{
			armState   = false;
			armNextPC  = reg[15].I;
			reg[15].I += 2;
		}
		else
		{
			armState   = true;
			reg[15].I &= 0xFFFFFFFC;
			armNextPC  = reg[15].I;
			reg[15].I += 4;
		}
		break;
	default:
		goto unknown_thumb;
	}
}
break;
case 0x48:
	// LDR R0,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[0].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x49:
	// LDR R1,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[1].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4a:
	// LDR R2,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[2].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4b:
	// LDR R3,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[3].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4c:
	// LDR R4,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[4].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4d:
	// LDR R5,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[5].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4e:
	// LDR R6,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[6].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x4f:
	// LDR R7,[PC, #Imm]
{
	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
	reg[7].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x50:
case 0x51:
	// STR Rd, [Rs, Rn]
{
	u32
	    address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	CPUWriteMemory(address,
	               reg[opcode & 7].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x52:
case 0x53:
	// STRH Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	CPUWriteHalfWord(address,
	                 reg[opcode & 7].W.W0);
	clockTicks += CPUUpdateTicksAccess16(address);
}
break;
case 0x54:
case 0x55:
	// STRB Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	CPUWriteByte(address,
	             reg[opcode & 7].B.B0);
	clockTicks += CPUUpdateTicksAccess16(address);
}
break;
case 0x56:
case 0x57:
	// LDSB Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	reg[opcode & 7].I = (s8)CPUReadByte(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x58:
case 0x59:
	// LDR Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	reg[opcode & 7].I = CPUReadMemory(address);
	clockTicks		 += CPUUpdateTicksAccess32(address);
}
break;
case 0x5a:
case 0x5b:
	// LDRH Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	reg[opcode & 7].I = CPUReadHalfWord(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x5c:
case 0x5d:
	// LDRB Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	reg[opcode & 7].I = CPUReadByte(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x5e:
case 0x5f:
	// LDSH Rd, [Rs, Rn]
{
	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
	reg[opcode & 7].I = (s16)CPUReadHalfWordSigned(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x60:
case 0x61:
case 0x62:
case 0x63:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
	// STR Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2);
	CPUWriteMemory(address,
	               reg[opcode & 7].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x68:
case 0x69:
case 0x6a:
case 0x6b:
case 0x6c:
case 0x6d:
case 0x6e:
case 0x6f:
	// LDR Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2);
	reg[opcode & 7].I = CPUReadMemory(address);
	clockTicks		 += CPUUpdateTicksAccess32(address);
}
break;
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
	// STRB Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31));
	CPUWriteByte(address,
	             reg[opcode & 7].B.B0);
	clockTicks += CPUUpdateTicksAccess16(address);
}
break;
case 0x78:
case 0x79:
case 0x7a:
case 0x7b:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f:
	// LDRB Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31));
	reg[opcode & 7].I = CPUReadByte(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
	// STRH Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1);
	CPUWriteHalfWord(address,
	                 reg[opcode & 7].W.W0);
	clockTicks += CPUUpdateTicksAccess16(address);
}
break;
case 0x88:
case 0x89:
case 0x8a:
case 0x8b:
case 0x8c:
case 0x8d:
case 0x8e:
case 0x8f:
	// LDRH Rd, [Rs, #Imm]
{
	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1);
	reg[opcode & 7].I = CPUReadHalfWord(address);
	clockTicks		 += CPUUpdateTicksAccess16(address);
}
break;
case 0x90:
	// STR R0, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[0].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x91:
	// STR R1, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[1].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x92:
	// STR R2, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[2].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x93:
	// STR R3, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[3].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x94:
	// STR R4, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[4].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x95:
	// STR R5, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[5].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x96:
	// STR R6, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[6].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x97:
	// STR R7, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	CPUWriteMemory(address, reg[7].I);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x98:
	// LDR R0, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[0].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x99:
	// LDR R1, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[1].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9a:
	// LDR R2, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[2].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9b:
	// LDR R3, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[3].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9c:
	// LDR R4, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[4].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9d:
	// LDR R5, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[5].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9e:
	// LDR R6, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[6].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0x9f:
	// LDR R7, [SP, #Imm]
{
	u32 address = reg[13].I + ((opcode & 255) << 2);
	reg[7].I	= CPUReadMemoryQuick(address);
	clockTicks += CPUUpdateTicksAccess32(address);
}
break;
case 0xa0:
	// ADD R0, PC, Imm
	reg[0].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa1:
	// ADD R1, PC, Imm
	reg[1].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa2:
	// ADD R2, PC, Imm
	reg[2].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa3:
	// ADD R3, PC, Imm
	reg[3].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa4:
	// ADD R4, PC, Imm
	reg[4].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa5:
	// ADD R5, PC, Imm
	reg[5].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa6:
	// ADD R6, PC, Imm
	reg[6].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa7:
	// ADD R7, PC, Imm
	reg[7].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
	break;
case 0xa8:
	// ADD R0, SP, Imm
	reg[0].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xa9:
	// ADD R1, SP, Imm
	reg[1].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xaa:
	// ADD R2, SP, Imm
	reg[2].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xab:
	// ADD R3, SP, Imm
	reg[3].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xac:
	// ADD R4, SP, Imm
	reg[4].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xad:
	// ADD R5, SP, Imm
	reg[5].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xae:
	// ADD R6, SP, Imm
	reg[6].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xaf:
	// ADD R7, SP, Imm
	reg[7].I = reg[13].I + ((opcode & 255) << 2);
	break;
case 0xb0:
{
	// ADD SP, Imm
	int offset = (opcode & 127) << 2;
	if (opcode & 0x80)
		offset = -offset;
	reg[13].I += offset;
}
break;
#define PUSH_REG(val, r) \
	if (opcode & (val)) { \
		CPUWriteMemory(address, reg[(r)].I); \
		if (offset) \
			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
		else \
			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
		offset	 = 1; \
		address += 4; \
	}
case 0xb4:
	// PUSH {Rlist}
{
	int offset	= 0;
	u32 temp	= reg[13].I - 4 * cpuBitsSet[opcode & 0xff];
	u32 address = temp & 0xFFFFFFFC;
	PUSH_REG(1, 0);
	PUSH_REG(2, 1);
	PUSH_REG(4, 2);
	PUSH_REG(8, 3);
	PUSH_REG(16, 4);
	PUSH_REG(32, 5);
	PUSH_REG(64, 6);
	PUSH_REG(128, 7);
	reg[13].I = temp;
}
break;
case 0xb5:
	// PUSH {Rlist, LR}
{
	int offset	= 0;
	u32 temp	= reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff];
	u32 address = temp & 0xFFFFFFFC;
	PUSH_REG(1, 0);
	PUSH_REG(2, 1);
	PUSH_REG(4, 2);
	PUSH_REG(8, 3);
	PUSH_REG(16, 4);
	PUSH_REG(32, 5);
	PUSH_REG(64, 6);
	PUSH_REG(128, 7);
	PUSH_REG(256, 14);
	reg[13].I = temp;
}
break;
#define POP_REG(val, r) \
	if (opcode & (val)) { \
		reg[(r)].I = CPUReadMemory(address); \
		if (offset) \
			clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \
		else \
			clockTicks += 2 + CPUUpdateTicksAccess32(address); \
		offset	 = 1; \
		address += 4; \
	}
case 0xbc:
	// POP {Rlist}
{
	int offset	= 0;
	u32 address = reg[13].I & 0xFFFFFFFC;
	u32 temp	= reg[13].I + 4 * cpuBitsSet[opcode & 0xFF];
	POP_REG(1, 0);
	POP_REG(2, 1);
	POP_REG(4, 2);
	POP_REG(8, 3);
	POP_REG(16, 4);
	POP_REG(32, 5);
	POP_REG(64, 6);
	POP_REG(128, 7);
	reg[13].I = temp;
}
break;
case 0xbd:
	// POP {Rlist, PC}
{
	int offset	= 0;
	u32 address = reg[13].I & 0xFFFFFFFC;
	u32 temp	= reg[13].I + 4 + 4 * cpuBitsSet[opcode & 0xFF];
	POP_REG(1, 0);
	POP_REG(2, 1);
	POP_REG(4, 2);
	POP_REG(8, 3);
	POP_REG(16, 4);
	POP_REG(32, 5);
	POP_REG(64, 6);
	POP_REG(128, 7);
	reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE);
	if (offset)
		clockTicks += CPUUpdateTicksAccessSeq32(address);
	else
		clockTicks += CPUUpdateTicksAccess32(address);
	armNextPC  = reg[15].I;
	reg[15].I += 2;
	reg[13].I  = temp;
}
break;
#define THUMB_STM_REG(val, r, b) \
	if (opcode & (val)) { \
		CPUWriteMemory(address, reg[(r)].I); \
		if (!offset) { \
			reg[(b)].I	= temp; \
			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
		} else \
			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
		offset	 = 1; \
		address += 4; \
	}
case 0xc0:
{
	// STM R0!, {Rlist}
	u32 address = reg[0].I & 0xFFFFFFFC;
	u32 temp	= reg[0].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 0);
	THUMB_STM_REG(2, 1, 0);
	THUMB_STM_REG(4, 2, 0);
	THUMB_STM_REG(8, 3, 0);
	THUMB_STM_REG(16, 4, 0);
	THUMB_STM_REG(32, 5, 0);
	THUMB_STM_REG(64, 6, 0);
	THUMB_STM_REG(128, 7, 0);
}
break;
case 0xc1:
{
	// STM R1!, {Rlist}
	u32 address = reg[1].I & 0xFFFFFFFC;
	u32 temp	= reg[1].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 1);
	THUMB_STM_REG(2, 1, 1);
	THUMB_STM_REG(4, 2, 1);
	THUMB_STM_REG(8, 3, 1);
	THUMB_STM_REG(16, 4, 1);
	THUMB_STM_REG(32, 5, 1);
	THUMB_STM_REG(64, 6, 1);
	THUMB_STM_REG(128, 7, 1);
}
break;
case 0xc2:
{
	// STM R2!, {Rlist}
	u32 address = reg[2].I & 0xFFFFFFFC;
	u32 temp	= reg[2].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 2);
	THUMB_STM_REG(2, 1, 2);
	THUMB_STM_REG(4, 2, 2);
	THUMB_STM_REG(8, 3, 2);
	THUMB_STM_REG(16, 4, 2);
	THUMB_STM_REG(32, 5, 2);
	THUMB_STM_REG(64, 6, 2);
	THUMB_STM_REG(128, 7, 2);
}
break;
case 0xc3:
{
	// STM R3!, {Rlist}
	u32 address = reg[3].I & 0xFFFFFFFC;
	u32 temp	= reg[3].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 3);
	THUMB_STM_REG(2, 1, 3);
	THUMB_STM_REG(4, 2, 3);
	THUMB_STM_REG(8, 3, 3);
	THUMB_STM_REG(16, 4, 3);
	THUMB_STM_REG(32, 5, 3);
	THUMB_STM_REG(64, 6, 3);
	THUMB_STM_REG(128, 7, 3);
}
break;
case 0xc4:
{
	// STM R4!, {Rlist}
	u32 address = reg[4].I & 0xFFFFFFFC;
	u32 temp	= reg[4].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 4);
	THUMB_STM_REG(2, 1, 4);
	THUMB_STM_REG(4, 2, 4);
	THUMB_STM_REG(8, 3, 4);
	THUMB_STM_REG(16, 4, 4);
	THUMB_STM_REG(32, 5, 4);
	THUMB_STM_REG(64, 6, 4);
	THUMB_STM_REG(128, 7, 4);
}
break;
case 0xc5:
{
	// STM R5!, {Rlist}
	u32 address = reg[5].I & 0xFFFFFFFC;
	u32 temp	= reg[5].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 5);
	THUMB_STM_REG(2, 1, 5);
	THUMB_STM_REG(4, 2, 5);
	THUMB_STM_REG(8, 3, 5);
	THUMB_STM_REG(16, 4, 5);
	THUMB_STM_REG(32, 5, 5);
	THUMB_STM_REG(64, 6, 5);
	THUMB_STM_REG(128, 7, 5);
}
break;
case 0xc6:
{
	// STM R6!, {Rlist}
	u32 address = reg[6].I & 0xFFFFFFFC;
	u32 temp	= reg[6].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 6);
	THUMB_STM_REG(2, 1, 6);
	THUMB_STM_REG(4, 2, 6);
	THUMB_STM_REG(8, 3, 6);
	THUMB_STM_REG(16, 4, 6);
	THUMB_STM_REG(32, 5, 6);
	THUMB_STM_REG(64, 6, 6);
	THUMB_STM_REG(128, 7, 6);
}
break;
case 0xc7:
{
	// STM R7!, {Rlist}
	u32 address = reg[7].I & 0xFFFFFFFC;
	u32 temp	= reg[7].I + 4 * cpuBitsSet[opcode & 0xff];
	int offset	= 0;
	// store
	THUMB_STM_REG(1, 0, 7);
	THUMB_STM_REG(2, 1, 7);
	THUMB_STM_REG(4, 2, 7);
	THUMB_STM_REG(8, 3, 7);
	THUMB_STM_REG(16, 4, 7);
	THUMB_STM_REG(32, 5, 7);
	THUMB_STM_REG(64, 6, 7);
	THUMB_STM_REG(128, 7, 7);
}
break;
#define THUMB_LDM_REG(val, r) \
	if (opcode & (val)) { \
		reg[(r)].I = CPUReadMemory(address); \
		if (offset) \
			clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \
		else \
			clockTicks += 2 + CPUUpdateTicksAccess32(address); \
		offset	 = 1; \
		address += 4; \
	}
case 0xc8:
{
	// LDM R0!, {Rlist}
	u32 address = reg[0].I & 0xFFFFFFFC;
	u32 temp	= reg[0].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 1))
		reg[0].I = temp;
}
break;
case 0xc9:
{
	// LDM R1!, {Rlist}
	u32 address = reg[1].I & 0xFFFFFFFC;
	u32 temp	= reg[1].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 2))
		reg[1].I = temp;
}
break;
case 0xca:
{
	// LDM R2!, {Rlist}
	u32 address = reg[2].I & 0xFFFFFFFC;
	u32 temp	= reg[2].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 4))
		reg[2].I = temp;
}
break;
case 0xcb:
{
	// LDM R3!, {Rlist}
	u32 address = reg[3].I & 0xFFFFFFFC;
	u32 temp	= reg[3].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 8))
		reg[3].I = temp;
}
break;
case 0xcc:
{
	// LDM R4!, {Rlist}
	u32 address = reg[4].I & 0xFFFFFFFC;
	u32 temp	= reg[4].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 16))
		reg[4].I = temp;
}
break;
case 0xcd:
{
	// LDM R5!, {Rlist}
	u32 address = reg[5].I & 0xFFFFFFFC;
	u32 temp	= reg[5].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 32))
		reg[5].I = temp;
}
break;
case 0xce:
{
	// LDM R6!, {Rlist}
	u32 address = reg[6].I & 0xFFFFFFFC;
	u32 temp	= reg[6].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 64))
		reg[6].I = temp;
}
break;
case 0xcf:
{
	// LDM R7!, {Rlist}
	u32 address = reg[7].I & 0xFFFFFFFC;
	u32 temp	= reg[7].I + 4 * cpuBitsSet[opcode & 0xFF];
	int offset	= 0;
	// load
	THUMB_LDM_REG(1, 0);
	THUMB_LDM_REG(2, 1);
	THUMB_LDM_REG(4, 2);
	THUMB_LDM_REG(8, 3);
	THUMB_LDM_REG(16, 4);
	THUMB_LDM_REG(32, 5);
	THUMB_LDM_REG(64, 6);
	THUMB_LDM_REG(128, 7);
	if (!(opcode & 128))
		reg[7].I = temp;
}
break;
case 0xd0:
	// BEQ offset
	if (Z_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd1:
	// BNE offset
	if (!Z_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd2:
	// BCS offset
	if (C_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd3:
	// BCC offset
	if (!C_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd4:
	// BMI offset
	if (N_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd5:
	// BPL offset
	if (!N_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd6:
	// BVS offset
	if (V_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd7:
	// BVC offset
	if (!V_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd8:
	// BHI offset
	if (C_FLAG && !Z_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xd9:
	// BLS offset
	if (!C_FLAG || Z_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xda:
	// BGE offset
	if (N_FLAG == V_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xdb:
	// BLT offset
	if (N_FLAG != V_FLAG)
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xdc:
	// BGT offset
	if (!Z_FLAG && (N_FLAG == V_FLAG))
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xdd:
	// BLE offset
	if (Z_FLAG || (N_FLAG != V_FLAG))
	{
		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
		armNextPC  = reg[15].I;
		reg[15].I += 2;
		clockTicks = 3;
	}
	break;
case 0xdf:
	// SWI #comment
	CPUSoftwareInterrupt(opcode & 0xFF);
	break;
case 0xe0:
case 0xe1:
case 0xe2:
case 0xe3:
case 0xe4:
case 0xe5:
case 0xe6:
case 0xe7:
{
	// B offset
	int offset = (opcode & 0x3FF) << 1;
	if (opcode & 0x0400)
		offset |= 0xFFFFF800;
	reg[15].I += offset;
	armNextPC  = reg[15].I;
	reg[15].I += 2;
}
break;
case 0xf0:
case 0xf1:
case 0xf2:
case 0xf3:
{
	// BLL #offset
	int offset = (opcode & 0x7FF);
	reg[14].I = reg[15].I + (offset << 12);
}
break;
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
{
	// BLL #offset
	int offset = (opcode & 0x7FF);
	reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000);
}
break;
case 0xf8:
case 0xf9:
case 0xfa:
case 0xfb:
case 0xfc:
case 0xfd:
case 0xfe:
case 0xff:
{
	// BLH #offset
	int offset = (opcode & 0x7FF);
	u32 temp   = reg[15].I - 2;
	reg[15].I  = (reg[14].I + (offset << 1)) & 0xFFFFFFFE;
	armNextPC  = reg[15].I;
	reg[15].I += 2;
	reg[14].I  = temp | 1;
}
break;
#ifdef BKPT_SUPPORT
case 0xbe:
	// BKPT #comment
	extern void (*dbgSignal)(int, int);
	reg[15].I -= 2;
	armNextPC -= 2;
	dbgSignal(5, opcode & 255);
	return;
#endif
case 0xb1:
case 0xb2:
case 0xb3:
case 0xb6:
case 0xb7:
case 0xb8:
case 0xb9:
case 0xba:
case 0xbb:
#ifndef BKPT_SUPPORT
case 0xbe:
#endif
case 0xbf:
case 0xde:
default:
unknown_thumb:
#ifdef GBA_LOGGING
	if (systemVerbose & VERBOSE_UNDEFINED)
		log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC - 2);
#endif
	CPUUndefinedException();
	break;
}
